#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
文件编码转换工具
功能：将指定目录下的所有文件转换为 UTF-8 编码格式

业务背景：
Unity 项目中的 C# 脚本文件可能因为历史原因使用了不同的编码格式（如 iso-8859-1），
导致中文注释显示为乱码。此工具用于批量统一转换为 UTF-8 编码。

设计决策：
1. 使用 chardet 库自动检测文件编码，提高转换准确性
2. 跳过已经是 UTF-8 的文件，避免不必要的处理
3. 保留原始文件作为备份，确保数据安全
4. 支持递归处理子目录
5. 提供详细的转换日志，方便追踪处理结果
"""

import os
import sys
import chardet
import shutil
from pathlib import Path
from datetime import datetime

def detect_encoding(file_path):
    """
    检测文件编码格式
    
    业务背景：不同文件可能使用不同的编码，需要先检测才能正确转换
    
    设计决策：
    - 读取文件的前 10000 字节进行检测，平衡准确性和性能
    - 如果检测失败，尝试常见的编码格式
    
    Args:
        file_path: 文件路径
        
    Returns:
        检测到的编码格式字符串
    """
    try:
        with open(file_path, 'rb') as f:
            raw_data = f.read(10000)
            if not raw_data:
                return 'utf-8'  # 空文件默认为 UTF-8
            
            result = chardet.detect(raw_data)
            encoding = result['encoding']
            confidence = result['confidence']
            
            # 如果置信度太低，尝试常见编码
            if confidence < 0.7:
                # 尝试 UTF-8
                try:
                    raw_data.decode('utf-8')
                    return 'utf-8'
                except:
                    pass
                
                # 尝试 GBK（常见的中文编码）
                try:
                    raw_data.decode('gbk')
                    return 'gbk'
                except:
                    pass
                
                # 尝试 iso-8859-1（检测到的编码）
                if encoding:
                    return encoding
            
            return encoding or 'utf-8'
    except Exception as e:
        print(f"检测文件 {file_path} 编码时出错: {e}")
        return 'utf-8'

def convert_file_to_utf8(file_path, backup=True):
    """
    将单个文件转换为 UTF-8 编码
    
    业务背景：需要将文件从当前编码转换为 UTF-8，同时保证内容不丢失
    
    设计决策：
    - 先检测编码，如果已经是 UTF-8 则跳过
    - 创建备份文件，确保数据安全
    - 使用错误处理策略 'ignore'，避免转换失败导致程序中断
    
    Args:
        file_path: 文件路径
        backup: 是否创建备份文件
        
    Returns:
        (是否转换成功, 原编码格式)
    """
    try:
        # 检测当前编码
        current_encoding = detect_encoding(file_path)
        
        # 如果已经是 UTF-8，跳过
        if current_encoding and current_encoding.lower() in ['utf-8', 'utf-8-sig']:
            return (False, 'utf-8')
        
        # 读取文件内容
        with open(file_path, 'rb') as f:
            raw_data = f.read()
        
        # 尝试解码
        try:
            if current_encoding:
                content = raw_data.decode(current_encoding)
            else:
                # 如果检测失败，尝试常见编码
                for enc in ['gbk', 'gb2312', 'iso-8859-1', 'latin-1', 'cp1252']:
                    try:
                        content = raw_data.decode(enc)
                        current_encoding = enc
                        break
                    except:
                        continue
                else:
                    # 如果都失败，使用 UTF-8 并忽略错误
                    content = raw_data.decode('utf-8', errors='ignore')
                    current_encoding = 'unknown'
        except Exception as e:
            print(f"解码文件 {file_path} 失败: {e}")
            return (False, current_encoding or 'unknown')
        
        # 创建备份
        if backup:
            backup_path = f"{file_path}.backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
            shutil.copy2(file_path, backup_path)
        
        # 写入 UTF-8 格式
        with open(file_path, 'w', encoding='utf-8', newline='') as f:
            f.write(content)
        
        return (True, current_encoding or 'unknown')
        
    except Exception as e:
        print(f"转换文件 {file_path} 时出错: {e}")
        return (False, 'error')

def convert_directory_to_utf8(directory_path, file_extensions=None, backup=True):
    """
    批量转换目录下的所有文件为 UTF-8
    
    业务背景：需要批量处理整个目录下的文件，提高效率
    
    设计决策：
    - 支持指定文件扩展名过滤，只处理相关文件
    - 递归处理子目录
    - 统计转换结果，提供详细的处理报告
    
    Args:
        directory_path: 目录路径
        file_extensions: 要处理的文件扩展名列表，None 表示处理所有文件
        backup: 是否创建备份文件
        
    Returns:
        转换统计信息字典
    """
    directory_path = Path(directory_path)
    if not directory_path.exists():
        print(f"错误：目录 {directory_path} 不存在")
        return None
    
    stats = {
        'total': 0,
        'converted': 0,
        'skipped': 0,
        'failed': 0,
        'details': []
    }
    
    # 如果没有指定扩展名，处理所有文本文件
    if file_extensions is None:
        file_extensions = ['.cs', '.md', '.txt', '.json', '.xml', '.shader', '.cginc', '.hlsl']
    
    # 遍历所有文件
    for file_path in directory_path.rglob('*'):
        if not file_path.is_file():
            continue
        
        # 检查文件扩展名
        if file_extensions and file_path.suffix.lower() not in file_extensions:
            continue
        
        stats['total'] += 1
        print(f"处理文件: {file_path.name}...", end=' ')
        
        success, original_encoding = convert_file_to_utf8(file_path, backup)
        
        if success:
            stats['converted'] += 1
            stats['details'].append({
                'file': str(file_path),
                'status': 'converted',
                'from': original_encoding
            })
            print(f"✓ 已转换 (从 {original_encoding} 到 UTF-8)")
        elif original_encoding == 'utf-8':
            stats['skipped'] += 1
            stats['details'].append({
                'file': str(file_path),
                'status': 'skipped',
                'reason': '已经是 UTF-8'
            })
            print("○ 跳过 (已经是 UTF-8)")
        else:
            stats['failed'] += 1
            stats['details'].append({
                'file': str(file_path),
                'status': 'failed',
                'reason': f'转换失败，原编码: {original_encoding}'
            })
            print(f"✗ 失败 (原编码: {original_encoding})")
    
    return stats

def main():
    """
    主函数
    
    业务背景：提供命令行接口，方便用户使用
    
    设计决策：
    - 默认处理 Scripts 目录
    - 支持命令行参数指定目录
    - 提供清晰的使用说明和结果报告
    """
    # 默认处理 Scripts 目录
    default_dir = Path(__file__).parent / 'Assets' / 'Scripts'
    
    # 如果提供了命令行参数，使用指定的目录
    if len(sys.argv) > 1:
        target_dir = Path(sys.argv[1])
    else:
        target_dir = default_dir
    
    print("=" * 60)
    print("文件编码转换工具 - 转换为 UTF-8")
    print("=" * 60)
    print(f"目标目录: {target_dir}")
    print(f"开始时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
    print("-" * 60)
    
    # 执行转换
    stats = convert_directory_to_utf8(
        target_dir,
        file_extensions=['.cs', '.md'],  # 只处理 C# 和 Markdown 文件
        backup=True
    )
    
    if stats:
        print("-" * 60)
        print("转换完成！")
        print(f"总文件数: {stats['total']}")
        print(f"成功转换: {stats['converted']}")
        print(f"跳过文件: {stats['skipped']} (已经是 UTF-8)")
        print(f"失败文件: {stats['failed']}")
        print(f"结束时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
        print("=" * 60)
        
        # 如果有备份文件，提示用户
        if stats['converted'] > 0:
            print("\n提示：已创建备份文件（.backup_*），如需恢复请手动操作")
    else:
        print("转换失败：无法访问目标目录")

if __name__ == '__main__':
    main()

